﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Linq;

namespace Web.Ajax.Data
{
	public class DataAttribute : System.Attribute
	{
		public string Table;
		public string Column;
		public string IdColumn="Id";
		public bool IdColumnInsertable;
		public bool Get = true;
		public bool Set = true;
		public Type ColumnAttribute = typeof(DataAttribute);

		public string GetTable(System.Type t)
		{
			if (string.IsNullOrEmpty(Table)&&t!=null)
				return t.Name;
			return Table;
		}
		
		public string GetColumn(MemberInfo mi)
		{
			if (string.IsNullOrEmpty(Column)&&mi!=null)
				return mi.Name;
			return Column;
		}
		public string GetColumnSql(MemberInfo mi)
		{
			return "[" + GetColumn(mi) + "]";
		}
		public void FromAltAttribute(object a)
		{
			if (a == null)
				return;
			if (a is System.Data.Linq.Mapping.ColumnAttribute)
			{
				var c = a as System.Data.Linq.Mapping.ColumnAttribute;
				if(!string.IsNullOrEmpty(c.Name))
					Column = c.Name;
			}
		}


		public string[] IdColumns
		{
			get
			{
				if (string.IsNullOrEmpty(IdColumn))
					return new string[]{"Id"};
				return IdColumn.Split(',');
			}
			set
			{
				if (value == null)
				{
					IdColumn = null;
					return;
				}
				IdColumn = string.Join(",", value);
			}
		}
		public bool HasCompositeId
		{
			get
			{
				var ids = IdColumns;
				if (ids != null && ids.Length > 1)
					return true;
				return false;
			}
		}

		public System.Type GetIdColumnType(System.Type t)
		{
			if (t==null || HasCompositeId)
				return null;
			var fi = t.GetField(IdColumn);
			if (fi != null)
				return fi.FieldType;
			var pi = t.GetProperty(IdColumn);
			if (pi != null)
				return pi.PropertyType;
			return null;
		}

		public class ColumnName
		{
			public string Name;
			public string SqlName;
		}

		public ColumnName[] GetColumns(System.Type t)
		{
			if (t == null)
				return null;
			var fields=t.GetFields();
			var props = t.GetProperties();
			var l = new List<MemberInfo>();
			l.AddRange(fields);
			l.AddRange(props);

			var cl = new List<ColumnName>();
			foreach (var m in l)
			{
				var da = GetMemberInfoDataAttribute(m, ColumnAttribute);
				if (da != null)
					cl.Add(new ColumnName() { Name = m.Name, SqlName = da.GetColumn(m) });
			}
			return cl.ToArray();
		}

		public ColumnName[] GetUpdatableColumns(System.Type t)
		{
			//Exclude the IdColumn if there is no composite key
			var cl = GetColumns(t);
			if (HasCompositeId)
				return cl;
			return (from c in cl where c.Name!=IdColumn select c).ToArray();
		}

		public ColumnName[] GetInsertableColumns(System.Type t)
		{
			var cl = GetColumns(t);
			if (HasCompositeId)
				return cl;
			//Exclude the IdColumn if there is no composite key and the IdColumn is NOT Insertable
			if (!IdColumnInsertable)
				return (from c in cl where c.Name != IdColumn select c).ToArray();
			return cl;
		}

		public ColumnName[] GetClausableColumns(System.Type t)
		{
			return GetColumns(t);
		}

		public static DataAttribute GetMemberInfoDataAttribute(MemberInfo m, Type ColumnAttribute)
		{
			var da = Reflection.Type.GetAttribute<DataAttribute>(m, false);
			if (da == null)
			{
				if (ColumnAttribute == null)
					ColumnAttribute = typeof(System.Data.Linq.Mapping.ColumnAttribute);
				da = new DataAttribute();
				var al = m.GetCustomAttributes(ColumnAttribute, false);
				if (al.Length == 0)
					return null;
				da.FromAltAttribute(al[0]);
			}
			return da;
		}

		public static DataAttribute GetByType(Type t)
		{
			var da = Reflection.Type.GetAttribute<DataAttribute>(t, false);
			if (da == null)
			{
				var ta = Reflection.Type.GetAttribute<System.Data.Linq.Mapping.TableAttribute>(t, false);
				if (ta != null)
				{
					da = new DataAttribute();
					da.Table = ta.Name;
					da.ColumnAttribute = typeof(System.Data.Linq.Mapping.ColumnAttribute);
				}
			}
			return da;
		}
	}
}
